/**
 * @brief 信号量，互斥锁，读写锁，范围锁模板，自旋锁，原子锁
 */

#ifndef __MUTEX_H__
#define __MUTEX_H__

#include <stdint.h>
#include <memory>
#include <thread>
#include <semaphore.h>
#include <pthread.h>
#include <atomic>
#include "noncopyable.h"

/**
 * @brief 信号量
 */
class Semaphore : Noncopyable
{
public:
    Semaphore(uint32_t count = 0);
    ~Semaphore();

    // 获取信号量
    void wait();
    // 释放信号量
    void notify();

private:
    sem_t m_semaphore;
};

/**
 * @brief 局部锁的模板实现
 */

template <class T>
class ScopedLockImpl
{
public:
    ScopedLockImpl(T &mutex)
        : m_mutex(mutex)
    {
        m_mutex.lock();
        is_locked = true;
    }

    ~ScopedLockImpl()
    {
        unlock();
    }

    void lock()
    {
        if (!is_locked)
        {
            m_mutex.lock();
            is_locked = true;
        }
    }

    void unlock()
    {
        if (is_locked)
        {
            m_mutex.unlock();
            is_locked = false;
        }
    }

private:
    T &m_mutex;
    bool is_locked;
};

/**
 * @brief 局部读锁模板实现
 */

template <class T>
class ReadScopedImpl
{
public:
    ReadScopedImpl(T &mutex)
        : m_mutex(mutex)
    {
        m_mutex.rdlock();
        m_locked = true;
    }

    ~ReadScopedImpl()
    {
        unlock();
    }

    void lock()
    {
        if (!m_locked)
        {
            m_mutex.rdlock();
            m_locked = true;
        }
    }

    void unlock()
    {
        if (m_locked)
        {
            m_mutex.unlock();
            m_locked = false;
        }
    }

private:
    T &m_mutex;
    bool m_locked;
};

/**
 * @brief 局部写锁模板实现
 */
template <class T>
class WriteScopedImpl
{
public:
    WriteScopedImpl(T &mutex)
        : m_mutex(mutex)
    {
        m_mutex.wrlock();
        m_locked = true;
    }

    ~WriteScopedImpl()
    {
        unlock();
    }

    void lock()
    {
        if (!m_locked)
        {
            m_mutex.wrlock();
            m_locked = true;
        }
    }

    void unlock()
    {
        if (m_locked)
        {
            m_mutex.unlock();
            m_locked = false;
        }
    }

private:
    T &m_mutex;
    bool m_locked;
};

/**
 * @brief 互斥量
 */

class Mutex : Noncopyable
{
public:
    // 局部锁
    typedef ScopedLockImpl<Mutex> Lock;

    Mutex()
    {
        pthread_mutex_init(&m_mutex, nullptr);
    }

    ~Mutex()
    {
        pthread_mutex_destroy(&m_mutex);
    }

    void lock()
    {
        pthread_mutex_lock(&m_mutex);
    }

    void unlock()
    {
        pthread_mutex_unlock(&m_mutex);
    }

private:
    pthread_mutex_t m_mutex;
};

/**
 * @brief 空锁用于测试
 */

class NullMutex : Noncopyable
{
public:
    // 局部锁
    typedef ScopedLockImpl<NullMutex> Lock;

    NullMutex() {}
    ~NullMutex() {}
    void lock() {}
    void unlock() {}
};

/**
 * @brief 读写互斥量
 */

class RWMutex : Noncopyable
{
public:
    // 局部读锁
    typedef ReadScopedImpl<RWMutex> ReadLock;
    // 局部写锁
    typedef WriteScopedImpl<RWMutex> WriteLock;

    RWMutex()
    {
        pthread_rwlock_init(&m_mutex, nullptr);
    }

    ~RWMutex()
    {
        pthread_rwlock_destroy(&m_mutex);
    }

    // 上读锁
    void rdlock()
    {
        pthread_rwlock_rdlock(&m_mutex);
    }

    // 上写锁
    void wrlock()
    {
        pthread_rwlock_wrlock(&m_mutex);
    }

    // 解锁
    void unlock()
    {
        pthread_rwlock_unlock(&m_mutex);
    }

private:
    pthread_rwlock_t m_mutex;
};

/**
 * @brief 读写空锁用于测试
 */

class NullRWMutex : Noncopyable
{
public:
    // 局部读锁
    typedef ReadScopedImpl<NullMutex> ReadLock;
    // 局部写锁
    typedef WriteScopedImpl<NullMutex> WriteLock;

    NullRWMutex() {}
    ~NullRWMutex() {}

    void rdlock() {}
    void wrlock() {}
    void unlock() {}
};

/**
 * @brief 自旋锁
 */
class Spinlock : Noncopyable
{
public:
    // 局部锁
    typedef ScopedLockImpl<Spinlock> Lock;
    Spinlock()
    {
        pthread_spin_init(&m_mutex, 0);
    }

    ~Spinlock()
    {
        pthread_spin_destroy(&m_mutex);
    }

    void lock()
    {
        pthread_spin_lock(&m_mutex);
    }

    void unlock()
    {
        pthread_spin_unlock(&m_mutex);
    }

private:
    pthread_spinlock_t m_mutex;
};

/**
 * @brief 原子锁
 */

class CASLock : Noncopyable
{
public:
    // 局部锁
    typedef ScopedLockImpl<CASLock> Lock;

    CASLock()
    {
        m_mutex.clear();
    }
    ~CASLock() {}

    void lock()
    {
        while (std::atomic_flag_test_and_set_explicit(&m_mutex, std::memory_order_acquire))
            ;
    }

    void unlock()
    {
        std::atomic_flag_clear_explicit(&m_mutex, std::memory_order_release);
    }

private:
    // 原子状态
    volatile std::atomic_flag m_mutex;
};

#endif